
package cnhy.salary.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cnhy.salary.domain.Department;
import cnhy.salary.domain.PostCfg;
import cnhy.salary.domain.dto.AttendanceListDto;
import cnhy.salary.domain.dto.AttendanceMaxDto;
import cnhy.salary.domain.dto.EmployeeDto;
import com.easy.query.api4j.sql.SQLWherePredicate;
import com.easy.query.core.expression.lambda.SQLExpression1;
import com.ruoyi.common.annotation.DataScope;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import io.swagger.annotations.*;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import lombok.*;
import com.ruoyi.common.core.page.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.enums.BusinessType;
import cnhy.salary.domain.AttendanceRecord;
import ling.common.*;
import ling.common.domain.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import java.io.IOException;
import cnhy.salary.domain.dto.AttendanceExportDto;

import static com.ruoyi.common.utils.DateUtils.parseDate;

/** 考勤记录 控制层
 * @author : He-LiangLiang@Outlook.com
 * @date : 2025-5-26
 */
@Api(tags = "考勤记录 功能接口")
@RestController
@RequestMapping("/salary/AttendanceRecord")
public class AttendanceRecordController extends EQueryController<AttendanceRecord>{
    

    //请假
    @ApiOperation("详情")
    @PreAuthorize("@ps.any(@pay.attendanceRecord.query)")
    @GetMapping(value = "/{id}")
    public Result<AttendanceRecord> getInfo(@PathVariable("id") Long id)
    {
       return super.getInfo(id);
    }
    
//    @ApiOperation("用户考勤明细")
//    @PreAuthorize("@ps.any(@pay.attendanceRecord.list)")
//    @GetMapping("listByUser")
//    public ResultRows<AttendanceListDto> listByUser(AttendanceListDto dto, PageSort pageRequest) {
//        if(dto.getDeptId()==null)
//        {
//            dto.setDeptId(getLoginUser().getUser().getDeptId());
//        }
//        gainPageDomain(pageRequest);
//        var pitem = queryHelper.queryable(AttendanceListDto.class)
//                .whereObject(dto)
//                .where(a -> a.ge(AttendanceListDto::getDayDate, DateUtil.beginOfMonth(DateUtils.addMonths(new Date(), -1))));
//        pitem.orderByObject(pageRequest);
//        var pData = pitem.toPageResult(pageRequest.getPageNum(), pageRequest.getPageSize());
//        return toResultRows(pData);
//    }
     @ApiOperation(value = "用户月考勤汇总",notes = "按月查询,返回数据中{normal正常、late迟到、missing缺卡,leave请假,data} 其中data为日明细列表，其他为数量")
     @PreAuthorize("@ps.any(@pay.attendanceRecord.list)")
     @GetMapping("monthByUser")
     public Result<Map> monthByUser(Long userId,Date date, PageSort pageRequest) {
        if(userId==null)
            return Result.bad("用户id错误");
         if (date == null)
             return ResultRows.bad("查询时间错误");
         gainPageDomain(pageRequest);
         //var begin = DateUtils.parseDateToStr("YYYYMM", dto.getDayDate());
         var pitem = queryHelper.queryable(AttendanceListDto.class)
                 .where(a -> a.eq(AttendanceListDto::getUserId, userId))
                 .where(a -> a.rangeClosed(AttendanceListDto::getDayDate, DateUtil.beginOfMonth(date),DateUtil.endOfMonth(date)));
         pitem.orderByObject(pageRequest);
         var list = pitem.toList();
         //0正常、1迟到、2缺卡,10补卡,20事假，21病假
         var d0 = 0;
         var d1 = 0;
         var d2 = 0;
         var d20 = 0;
         for (var item : list) {
             if (!StringUtils.isBlank(item.getLeaveType())) {
                 d20++;
                 continue;
             }
             if (item.getAttendanceResult() == null)
                 continue;
             if (item.getAttendanceResult() == 0)
                 d0++;
             else if (item.getAttendanceResult() == 1)
                 d1++;
             else if (item.getAttendanceResult() == 2)
                 d2++;
             else if (item.getAttendanceResult() == 10)
                 d0++;
         }
         var map = new HashMap<String, Object>();
         map.put("normal", d0);//正常
         map.put("late", d1);//迟到
         map.put("missing", d2);//缺卡
         map.put("leave", d20);//请假
         map.put("data",list);
         return Result.ok(map);
     }
     @ApiOperation(value = "用户月考勤,按日汇总",notes = "按月查询,参数：dayDate要查询的月份，userId要查询的用户id(注意不是员工id)")
     @PreAuthorize("@ps.any(@pay.attendanceRecord.list)")
     @GetMapping("monthByDay")
     public ResultRows<AttendanceMaxDto> monthByDay(AttendanceMaxDto dto, PageSort pageRequest) {

        if(dto.getDayDate()==null)
            return  ResultRows.bad("查询时间错误");
         gainPageDomain(pageRequest);
         var begin=DateUtils.parseDateToStr("YYYYMM",dto.getDayDate());
         var pitem = queryHelper.queryable(AttendanceMaxDto.class)
                 .where(dto.getUserId()!=null,a -> a.eq(AttendanceMaxDto::getUserId,dto.getUserId()))
                 .where(a->a.or(p->{
                     p.likeMatchLeft(AttendanceMaxDto::getDateFmt,begin);
                     p.likeMatchLeft(AttendanceMaxDto::getLeaveDate,begin);
                 }));
         pitem.orderByObject(pageRequest);
         var pData = pitem.toPageResult(pageRequest.getPageNum(), pageRequest.getPageSize());
         return toResultRows(pData);
     }

     @ApiOperation("分页列表")
     @PreAuthorize("@ps.any(@pay.attendanceRecord.list)")
     @GetMapping("list")
     public ResultRows<AttendanceRecord> list(AttendanceRecord dto, Integer[] resultExtArr, PageDomain pageRequest) {
         SQLExpression1<SQLWherePredicate<AttendanceRecord>> where = null;

         // ========== 修改开始 ==========
         where = p -> {
             p.in(ArrayUtil.isNotEmpty(resultExtArr), AttendanceRecord::getResultExt, resultExtArr);

             // 时间范围条件（安全处理）
             if (dto.getQueryTime() != null) {
                 p.rangeClosed(true, AttendanceRecord::getCreatedTime, true,
                         DateUtil.beginOfDay(dto.getCreatedTime()),
                         true,
                         DateUtil.endOfDay(dto.getCreatedTime()));
             }
         };
         // ========== 修改结束 ==========

         var re = queryPage(dto, pageRequest, where);
         var data = re.getRows();
         if (!data.isEmpty()) {
             attFill(data);
         }
         return re;
     }

     private void attFill(List<AttendanceRecord> data) {

         var ids = data.stream().map(p -> p.getPostId()).distinct().collect(Collectors.toList());
         var select = queryHelper.entityQuery(PostCfg.class).where(p -> p.id().in(ids)).toList();
         DataUtil.findSet(data, select, (p, p1) -> Objects.equals(p.getPostId(), p1.getId()), (p, p1) -> p.ExtendMapSet("postName", p1.getName()));
         var ids2 = data.stream().map(p -> p.getDeptId()).distinct().collect(Collectors.toList());
         var select2 = queryHelper.entityQuery(Department.class).where(p -> p.deptId().in(ids2)).toList();
         DataUtil.findSet(data, select2, (p, p1) -> Objects.equals(p.getDeptId(), p1.getDeptId()),
                 (p, p1) -> {
                     p.ExtendMapSet("deptName", p1.getDeptName());
                     p.ExtendMapSet("leader", p1.getLeader());
                 });

     }


     @ApiOperation("新增")
    @PreAuthorize("@ps.any(@pay.attendanceRecord.add)")
    @Log(title = "考勤记录", businessType = BusinessType.INSERT)
    @PostMapping
    public Result add(@Validated @RequestBody AttendanceRecord entity){

        var empl=queryHelper.queryable(EmployeeDto.class).where(p->p.eq(EmployeeDto::getUserId,entity.getUserId())).firstOrNull();
        entity.setDeptId(empl.getDeptId());
        entity.setDeptName(empl.getDeptName());
        entity.setPostId(empl.getPost());
        entity.setOrderNum(empl.getOrderNum());
        return super.add(entity);
    }
     @ApiOperation(value = "补卡",notes = "只需要{id}")
     @PreAuthorize("@ps.any(@pay.attendanceRecord.edit)")
     @Log(title = "考勤记录", businessType = BusinessType.UPDATE)
     @PostMapping("remedy")
     @DataScope
     public Result remedy( @RequestBody AttendanceRecord entity){

         var old=queryHelper.entityQuery(AttendanceRecord.class).whereById(entity.getId()).firstOrNull();
         if(old==null)
             return  Result.bad("无法找到数据,可能是无权限或数据不存在");
         if(old.getResultExt()!=1&&old.getResultExt()!=2)
                return Result.bad("迟到或缺卡才可以补卡");
         old.setResultExt(10);
         return super.edit(old);
     }
    
    @ApiOperation("删除")
    @PreAuthorize("@ps.any(@pay.attendanceRecord.remove)")
    @Log(title = "考勤记录", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public Result remove(@PathVariable("ids") Long[] ids){
        return super.remove(Arrays.stream(ids).toArray());
    }
    
    @ApiOperation("编辑")
    @PreAuthorize("@ps.any(@pay.attendanceRecord.edit)")
    @Log(title = "考勤记录", businessType = BusinessType.UPDATE)
    @PutMapping
    public  Result edit(@Validated @RequestBody AttendanceRecord entity){
        return super.edit(entity);
    }
    
    @ApiOperation("导出")
    @PreAuthorize("@ps.any(@pay.attendanceRecord.export)")
    @Log(title = "考勤记录", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(AttendanceRecord entity, Long postId, Long deptId, String userName, HttpServletResponse response) throws IOException{
        // 根据工资月份规则计算日期范围
        Date startDate, endDate;
        var time = entity.getDayDate();
        if (time == null) {
            time = new Date(); // 如果未指定日期，使用当前日期
        }
        
        var targetMonth = DateUtil.month(time); // 获取月份(0-11)

        if (targetMonth == 0) { // 1月
            // 1月工资：1.1-1.30
            startDate = DateUtil.beginOfMonth(time); // 1.1
            endDate = DateUtil.offsetDay(DateUtil.endOfMonth(time), -1); // 1.30
        } else if (targetMonth == 11) { // 12月
            // 12月工资：11.30-12.31
            startDate = DateUtil.offsetDay(DateUtil.endOfMonth(DateUtil.offsetMonth(time, -1)), -1); // 11.30
            endDate = DateUtil.endOfMonth(time); // 12.31
        } else { // 2-11月
            // 其他月份：上月最后一天到当月倒数第二天
            startDate = DateUtil.endOfMonth(DateUtil.offsetMonth(time, -1)); // 上月最后一天
            endDate = DateUtil.offsetDay(DateUtil.endOfMonth(time), -1); // 当月倒数第二天
        }

        // 查询指定日期范围内的考勤记录
        var records = queryHelper.queryable(AttendanceRecord.class)
                .where(a -> a.ge(AttendanceRecord::getDayDate, startDate))
                .where(a -> a.le(AttendanceRecord::getDayDate, endDate))
                // 如果postId不为空，则添加岗位筛选条件
                .where(postId != null, a -> a.eq(AttendanceRecord::getPostId, postId))
                // 如果deptId不为空，则添加部门筛选条件
                .where(deptId != null, a -> a.eq(AttendanceRecord::getDeptId, deptId))
                // 如果userName不为空，则添加用户名筛选条件
                .where(StringUtils.isNotEmpty(userName), a -> a.like(AttendanceRecord::getUserName, "%" + userName + "%"))
                // 先按用户名排序，再按orderNum排序
                .orderByAsc(p -> p.column(AttendanceRecord::getOrderNum))
                .orderByAsc(p -> p.column(AttendanceRecord::getUserName))
                .toList();

        // 按员工分组
        Map<String, List<AttendanceRecord>> groupedRecords = records.stream()
                .collect(Collectors.groupingBy(AttendanceRecord::getUserName));

        List<AttendanceExportDto> exportList = new ArrayList<>();

        // 处理每个员工的考勤记录
        for (Map.Entry<String, List<AttendanceRecord>> entry : groupedRecords.entrySet()) {
            AttendanceExportDto dto = new AttendanceExportDto();
            dto.setUserName(entry.getKey());
            
            // 获取该用户任意一条记录的orderNum
            dto.setOrderNum(entry.getValue().stream()
                .filter(r -> r.getOrderNum() != null)
                .findFirst()
                .map(AttendanceRecord::getOrderNum)
                .orElse(null));
            
            // 处理每天的考勤状态
            Map<String, String> dateStatusMap = entry.getValue().stream()
                    .collect(Collectors.toMap(
                            r -> DateUtils.parseDateToStr("yyyy/M/d", r.getDayDate()),
                            r -> getStatusText(r.getResultExt()),
                            (existing, replacement) -> existing
                    ));

            // 遍历日期范围内的每一天
            Date currentDate = DateUtil.date(startDate);
            while (currentDate.compareTo(endDate) <= 0) {
                String dateStr = DateUtils.parseDateToStr("yyyy/M/d", currentDate);
                dto.setAttendanceStatus(dateStr, dateStatusMap.getOrDefault(dateStr, ""));
                currentDate = DateUtil.offsetDay(currentDate, 1);
            }

            exportList.add(dto);
        }

        // 获取所有日期列
        List<String> columnNames = new ArrayList<>();
        Date currentDate = DateUtil.date(startDate);
        while (currentDate.compareTo(endDate) <= 0) {
            columnNames.add(DateUtils.parseDateToStr("yyyy/M/d", currentDate));
            currentDate = DateUtil.offsetDay(currentDate, 1);
        }

        // 按orderNum排序
        exportList.sort(Comparator.comparing(AttendanceExportDto::getOrderNum, Comparator.nullsFirst(Comparator.naturalOrder())));

        // 导出Excel（使用自定义导出方法）
        exportWithDynamicColumns(response, exportList, "考勤记录", columnNames);
    }

    private void exportWithDynamicColumns(HttpServletResponse response, List<AttendanceExportDto> list, String sheetName, List<String> columnNames) throws IOException {
        try (SXSSFWorkbook wb = new SXSSFWorkbook(500)) {
            Sheet sheet = wb.createSheet(sheetName);
            
            // 创建标题行
            Row headerRow = sheet.createRow(0);
            headerRow.createCell(0).setCellValue("员工姓名");
            for (int i = 0; i < columnNames.size(); i++) {
                headerRow.createCell(i + 1).setCellValue(columnNames.get(i));
            }

            // 填充数据
            for (int i = 0; i < list.size(); i++) {
                AttendanceExportDto dto = list.get(i);
                Row row = sheet.createRow(i + 1);
                
                // 设置员工姓名
                row.createCell(0).setCellValue(dto.getUserName());
                
                // 设置每天的考勤状态
                for (int j = 0; j < columnNames.size(); j++) {
                    String columnName = columnNames.get(j);
                    String value = dto.getAttendanceStatus(columnName);
                    row.createCell(j + 1).setCellValue(value);
                }
            }

            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=" + sheetName + ".xlsx");

            // 写入响应流
            wb.write(response.getOutputStream());
            wb.dispose();
        } catch (Exception e) {
            throw new RuntimeException("导出Excel异常", e);
        }
    }

    private String getStatusText(Integer resultExt) {
        if (resultExt == null) return "";
        switch (resultExt) {
            case 0: return "正常";
            case 1: return "迟到";
            case 2: return "缺卡";
            case 10: return "补卡";
            case 20: return "事假";
            case 21: return "病假";
            default: return "";
        }
    }
}